package org.aplombh.java.awcing.basic.dp.knapsack;

import java.io.*;
import java.util.Scanner;

/**
 * 有 N 组物品和一个容量是 V 的背包。
 * <p>
 * 每组物品有若干个，同一组内的物品最多只能选一个。
 * 每件物品的体积是 vij，价值是 wij，其中 i 是组号，j 是组内编号。
 * <p>
 * 求解将哪些物品装入背包，可使物品总体积不超过背包容量，且总价值最大。
 * <p>
 * 输出最大价值。
 * <p>
 * 输入格式
 * 第一行有两个整数 N，V，用空格隔开，分别表示物品组数和背包容量。
 * <p>
 * 接下来有 N 组数据：
 * <p>
 * 每组数据第一行有一个整数 Si，表示第 i 个物品组的物品数量；
 * 每组数据接下来有 Si 行，每行有两个整数 vij,wij，用空格隔开，分别表示第 i 个物品组的第 j 个物品的体积和价值；
 * 输出格式
 * 输出一个整数，表示最大价值。
 * <p>
 * 数据范围
 * 0<N,V≤100
 * 0<Si≤100
 * 0<vij,wij≤100
 * 输入样例
 * 3 5
 * 2
 * 1 2
 * 2 4
 * 1
 * 3 4
 * 1
 * 4 5
 * 输出样例：
 * 8
 */
public class GroupingKnapsackProblem_9 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();

        GroupingKnapsackProblem multipleKnapsackProblem = new GroupingKnapsackProblem(n, m);

        for (int i = 1; i <= n; i++) {
            int s = scanner.nextInt();
            for (int j = 1; j <= s; j++) {
                multipleKnapsackProblem.v[i][j] = scanner.nextInt();
                multipleKnapsackProblem.w[i][j] = scanner.nextInt();
            }
        }
        System.out.println(multipleKnapsackProblem.solve());
    }
}

class Test {
    public static void main(String[] args) throws IOException {

        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        String[] str = reader.readLine().split(" ");
        int n = Integer.parseInt(str[0]);
        int m = Integer.parseInt(str[1]);

        GroupingKnapsackProblem multipleKnapsackProblem = new GroupingKnapsackProblem(n, m);

        for (int i = 1; i <= n; i++) {
            int s = Integer.parseInt(reader.readLine());
            multipleKnapsackProblem.v[i][0] = s;
            multipleKnapsackProblem.w[i][0] = s;
            for (int j = 1; j <= s; j++) {
                String[] str1 = reader.readLine().split(" ");
                multipleKnapsackProblem.v[i][j] = Integer.parseInt(str1[0]);
                multipleKnapsackProblem.w[i][j] = Integer.parseInt(str1[1]);
            }
        }
        System.out.println(multipleKnapsackProblem.solve());

    }
}

class GroupingKnapsackProblem {
    public static final int N = 12;
    int n, m;
    int[] f = new int[N];
    int[][] v = new int[N][N];
    int[][] w = new int[N][N];
    int[][][] path = new int[N][N][N];

    public GroupingKnapsackProblem(int n, int m) {
        this.n = n;
        this.m = m;
    }

    public int solve() {
        for (int i = 1; i <= n; i++) {
            for (int j = m; j > 0; j--) {
                // 从前往后判断
                for (int k = 1; v[i][k] != 0; k++) {
                    if (j >= v[i][k]) {
                        if (f[j] < f[j - v[i][k]] + w[i][k]) {
                            f[j] = f[j - v[i][k]] + w[i][k];
                            path[i][j][k] = 1;
                        }
                    }
                }
            }
        }
        path();
        return f[m];
    }

    public void path() {
        for (int i = n, j = m; i > 0 && j > 0; ) {
            // 和判断顺序相反，从后往前
            for (int k = v[i][0]; k > 0; k--) {
                if (path[i][j][k] == 1 ) {
                    System.out.println(i + " " + k + " v:" + v[i][k] + " w:" + w[i][k]);
                    j -= v[i][k];
                    i--;
                    break;
                } else {
                    i--;
                }
            }
        }
    }
}
